﻿/*----------------------------------------------------------------
// 公司名称：公司名称
// 
// 产品名称：Gaf
//
// 创 建 人：netcasewqs
// 创建日期：2022/3/4
// 邮    箱：netcasewqs@qq.com
//
// Copyright (C) 2022 Gaf，保留所有权利。
//
//----------------------------------------------------------------*/

using System.Runtime.InteropServices;

namespace Gaf.Impl;

internal sealed class UnmanagedLibrary : IDisposable
{
    private readonly string TraceLabel;

    private readonly IntPtr _handle;

    internal UnmanagedLibrary(string libraryName, IntPtr libraryHandle)
    {
        if (string.IsNullOrWhiteSpace(libraryName))
        {
            throw new ArgumentException("A valid library name is expected.", nameof(libraryName));
        }
        if (libraryHandle.IsNullOrInvalid())
        {
            throw new ArgumentNullException(nameof(libraryHandle));
        }

        TraceLabel = $"UnmanagedLibrary[{libraryName}]";

        _handle = libraryHandle;
    }

    [DllImport(Win32.LibraryName, CharSet = CharSet.Auto, BestFitMapping = false, SetLastError = true)]
    private static extern IntPtr GetProcAddress(IntPtr lib, string funcName);

    [DllImport(Win32.LibraryName, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool FreeLibrary(IntPtr lib);

    public TDelegate? GetUnmanagedFunction<TDelegate>(string functionName) where TDelegate : class
    {
        IntPtr p = GetProcAddress(_handle, functionName);

        if (p == IntPtr.Zero) return null;
        var result = (TDelegate)(object)Marshal.GetDelegateForFunctionPointer(p, typeof(TDelegate));

        return result;
    }

    public void Dispose()
    {
        if (_handle != IntPtr.Zero)
        {
            FreeLibrary(_handle);
        }
    }

    public override string ToString() => TraceLabel;
}

//internal class NativeBundleActivator : IBundleActivator, IDisposable
//{
//    private readonly UnmanagedLibrary _handle;
//    private readonly Action StartAction;
//    private readonly Action StopAction;

//    private NativeBundleActivator(UnmanagedLibrary handle, Action start, Action stop)
//    {
//        _handle = handle;
//        StartAction = start;
//        StopAction = stop;
//    }

//    public void Dispose() => _handle?.Dispose();

//    public void Start(IBundleContext context) => StartAction?.Invoke();

//    public void Stop(IBundleContext context) => StopAction?.Invoke();

//    public static NativeBundleActivator Create(UnmanagedLibrary handle, string strStartMethod, string strStopMethod)
//    {
//        Action startMethod, stopMethod;
//        PopulateStartAndStopMethod(handle, strStartMethod, strStopMethod, out startMethod, out stopMethod);

//        return new NativeBundleActivator(handle, startMethod, stopMethod);
//    }

//    private static void PopulateStartAndStopMethod(UnmanagedLibrary handle, string strStartMethod, string strStopMethod, out Action startMethod, out Action stopMethod)
//    {
//        strStartMethod = strStartMethod ?? "Start";
//        strStopMethod = strStopMethod ?? "Stop";

//        startMethod = handle.GetUnmanagedFunction<Action>(strStartMethod);
//        if (startMethod == null) startMethod = handle.GetUnmanagedFunction<Action>("Open");
//        //if (startMethod == null)
//        //    throw new ConfigurationErrorsException($"Start method '{strStartMethod}' not found in native bundle Activator '{handle} ");

//        stopMethod = handle.GetUnmanagedFunction<Action>(strStopMethod);
//        if (stopMethod == null) stopMethod = handle.GetUnmanagedFunction<Action>("Close");
//        //if (stopMethod == null)
//        //    throw new ConfigurationErrorsException($"Close method '{strStartMethod}' not found in native bundle Activator '{handle} ");
//    }

//    public override string ToString() => _handle?.ToString();
//}